import {
  AfterViewInit,
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  EventEmitter,
  Input,
  OnChanges,
  OnDestroy,
  Output,
  SimpleChanges,
  TemplateRef,
  ViewEncapsulation,
} from '@angular/core';
import { animate, group, state, style, transition, trigger, AnimationEvent } from '@angular/animations';
import { Subject } from 'rxjs';
import { InputBoolean } from '../core/utils/convert';
import { TypeUtils } from '../core/utils/type';
import { LvListItemLayout } from '../core/types';
import { MotionDuration, MotionFunc } from '../core/animation/motion';
import { ListComponent } from './list.component';

@Component({
  selector: 'lv-list-item, [lv-list-item]',
  templateUrl: './list-item.component.html',
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
  host: {
    class: 'lv-list-item',
    '[class.lv-list-item-horizontal]': "layout === 'horizontal'",
    '[class.lv-list-item-vertical]': "layout === 'vertical'",
  },
  animations: [
    trigger('showExpand', [
      state('hide', style({ opacity: 0, height: 0, overflow: 'hidden' })),
      state('show', style({ opacity: 1, height: '*', overflow: 'hidden' })),
      transition('* => show', [
        group([
          style({ opacity: 0, height: 0 }),
          animate(`${MotionDuration.MD} ${MotionFunc.EASE_IN_OUT}`, style({ opacity: 1 })),
          animate(`${MotionDuration.MD} ${MotionFunc.EASE}`, style({ height: '*' })),
        ]),
      ]),
      transition(
        'show => hide',
        group([
          style({ opacity: 1, height: '*' }),
          animate(`${MotionDuration.SM} ${MotionFunc.EASE_IN_OUT}`, style({ opacity: 0 })),
          animate(`${MotionDuration.SM} ${MotionFunc.EASE}`, style({ height: 0 })),
        ]),
      ),
    ]),
  ],
})
export class ListItemComponent implements OnChanges, AfterViewInit, OnDestroy {
  @Input() @InputBoolean() lvExpand; // 是否展开
  @Input() lvExtra: TemplateRef<void>;
  @Input() lvExpandRender: TemplateRef<void>;
  @Input() lvContent: string | TemplateRef<void>;
  @Input() lvActions: Array<TemplateRef<void>> = [];
  @Output() lvExpandChange = new EventEmitter<boolean>(); // 展开折叠回调事件
  @Input() lvExpandIcon: string | TemplateRef<any> = 'lv-icon-triangle-down'; // 展开折叠图标

  typeUtils = TypeUtils;
  animationState = 'void'; // 动画状态

  layout: LvListItemLayout;
  layout$ = new Subject<LvListItemLayout>();

  constructor(
    private parentCom: ListComponent,
    private cdr: ChangeDetectorRef,
  ) {}

  ngOnDestroy(): void {
    if (this.layout$) {
      this.layout$.unsubscribe();
    }
  }

  /**
   * 设置动画状态
   * @param value 状态参数
   */
  setAnimationState(value: 'show' | 'hide'): void {
    this.animationState = value;
    this.cdr.markForCheck();
  }

  expanded(e: MouseEvent): void {
    e.stopPropagation();
    this.setAnimationState(this.animationState === 'show' ? 'hide' : 'show');
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.lvExpand) {
      this.setAnimationState(changes.lvExpand.currentValue ? 'show' : 'hide');
    }
  }

  ngAfterViewInit(): void {
    this.parentCom?.itemLayout$.subscribe((res): void => {
      this.layout = res;
      this.layout$.next(res);
      this.cdr.markForCheck();
    });
  }

  /**
   * 监听动画执行
   */
  onAnimationDone(event: AnimationEvent): void {
    if (event.fromState === 'show' && event.toState === 'hide') {
      this.lvExpand = false;
    }

    if (event.fromState === 'hide' && event.toState === 'show') {
      this.lvExpand = true;
    }

    this.lvExpandChange.emit(this.lvExpand);
  }
}
